#include "parser.h"
#include <string>
#include <iostream>
#include <sstream>
#include "common.h"


#define STRING_TYPE (0)
#define INT_TYPE (1)
#define FLOAT_TYPE (2)


#define SET_ERROR(X, C) do{_setError(X,#X, C);}while(0)


using namespace wolv::condition;



Parser::Parser()
{

}

Parser::~Parser()
{

}

void Parser::_setError( int code, const std::string& message ,const char * near)
{
	errorCode_ = code;
	std::ostringstream oss;
	std::string strNear = near;
	size_t pos = strNear.find('\n');
	strNear = strNear.substr(0, pos);

	oss << message << " ,line: " << currentLine_ << " ,near: " << strNear;
	errorMessage_ = oss.str();
}

void wolv::condition::Parser::_clearError()
{
	errorCode_ = 0;
	errorMessage_ = "";
	currentLine_ = 0;
}

int wolv::condition::Parser::Parse( const std::string& str, Script& script )
{
	const char * start = str.c_str(); 
	std::string name;
	std::string successAction, failAction;
	int op;
	bool AllowEOF = false;
	currentLine_ = 0;

	while (true)
	{
		++currentLine_;
		AllowEOF = false;

		name = _parseName(start);
		if (GetLastError()  != SUCCESS)
		{
			AllowEOF = true;
			break;
		}

		Variable var1 = _parseVaribale(start);
		if (GetLastError()  != SUCCESS)
		{
			AllowEOF = true;
			break;
		}

		op = _parseOperation(start);
		if (GetLastError()  != SUCCESS)
		{
			break;
		}

		Variable var2 = _parseVaribale(start);
		if (GetLastError()  != SUCCESS)
		{
			AllowEOF = true;
			break;
		}

		successAction = _parseAction(start);
		if (GetLastError()  != SUCCESS)
		{
			break;
		}

		failAction = _parseAction(start);
		if (GetLastError()  != SUCCESS)
		{
			break;
		}


		Condition cd(op, var1, var2, successAction, failAction);

		script.AddCondition(name, cd);

		_parseBreak(start);
		if (GetLastError()  != SUCCESS)
		{
			AllowEOF = true;
			break;
		}
	}

	if (GetLastError()  != SUCCESS)
	{
		if (AllowEOF && GetLastError() == PARSER_ENF_OF_FILE)
		{
			_clearError();
            script.SetRawScript(str);

			return 0;
		}
		else
		{
			return -1;
		}
	}

    script.SetRawScript(str);

	return 0;
}

Variable Parser::_parseVaribale( const char*& start )
{
	const char * begin = start;

	_clearError();

	std::string str = _getWord(start);

	if (str.empty())
	{
		SET_ERROR(PARSER_ENF_OF_FILE, begin);
		return Variable();
	}

	if (str[0] == '$')
	{
		if (str.size() < 2)
		{
			SET_ERROR(PARSER_VARIABLE_NAME_ERROR, begin);
			return Variable();
		}

		return Variable(str.substr(1, str.size() - 1));
	}
	if (str[0] == '[')
	{
		if (str[str.size()-1] != ']')
		{
			SET_ERROR(PARSER_DATA_FORMAT_ERROR, begin);
			return Variable();
		}

		VariableValue var;
		int count = 0;
		std::string key = "";
		std::string data = "";
		str = str.substr(1, str.size() - 2);
		while (!str.empty())
		{
			++count;
			if (count == 1)
			{
				key = REGION_OPERATION_START;
			}
			else if (count == 2)
			{
				key = REGION_OPERATION_END;
			}
			else
			{
				SET_ERROR(PARSER_DATA_FORMAT_ERROR, begin);
				break;
			}

			size_t pos = str.find(',');
			data = str.substr(0, pos);
			VariableValue item = data.c_str();
			item.StringTypeConvert();
			var.append(key, item);

			if (pos == std::string::npos)
			{
				break;
			}
			str = str.substr(pos + 1);
		}

		if (count != 2)
		{
			SET_ERROR(PARSER_DATA_FORMAT_ERROR, begin);
		}

		return var;
	}
	if (str[0] == '(')
	{
		if (str[str.size()-1] != ')')
		{
			SET_ERROR(PARSER_DATA_FORMAT_ERROR, begin);
			return Variable();
		}

		VariableValue var;
		std::string data = "";
		str = str.substr(1, str.size() - 2);
		while (!str.empty())
		{
			size_t pos = str.find(',');

			data = str.substr(0, pos);
			VariableValue item = data.c_str();
			item.StringTypeConvert();
			var.append(item);

			if (pos == std::string::npos)
			{
				break;
			}

			str = str.substr(pos + 1);
		}
		return var;
	}
	else
	{
		VariableValue var = str.c_str();
		var.StringTypeConvert();

		return var;
	}
}

int wolv::condition::Parser::_parseOperation( const char*& start )
{
	const char * begin = start;

	_clearError();

	std::string str = _getWord(start);

	if (str.empty())
	{
		SET_ERROR(PARSER_ENF_OF_FILE, begin);
		return UNKNOWN;
	}

	int op = String2Op(str);
	if (op == UNKNOWN)
	{
		SET_ERROR(PARSER_OPERATION_FORMAT_ERROR, begin);
		return UNKNOWN;
	}

	return op;
}

std::string wolv::condition::Parser::_parseAction( const char*& start )
{
	const char * begin = start;

	_clearError();

	std::string str = _getWord(start);

	if (str.empty())
	{
		SET_ERROR(PARSER_ENF_OF_FILE, begin);
		return "";
	}

	return str;
}

std::string Parser::_parseName( const char*& start )
{
	const char * begin = start;

	_clearError();

	std::string str = _getWord(start);

	if (str.empty())
	{
		SET_ERROR(PARSER_ENF_OF_FILE, begin);
		return "";
	}

	if (str.empty())
	{
		SET_ERROR(PARSER_LINE_WITHOUT_NAME, begin);
		return "";
	}

	if (str[str.size() - 1] != ':')
	{
		SET_ERROR(PARSER_NAME_FORMAT_ERROR, begin);
		return "";
	}

	return str.substr(0, str.size() - 1);
}

void wolv::condition::Parser::_parseBreak( const char*& start )
{
	const char * begin = start;

	_clearError();

	std::string str = _getWord(start, true);

	if (str.empty())
	{
		SET_ERROR(PARSER_ENF_OF_FILE, begin);
		return;
	}

	if (str != "\n")
	{
		SET_ERROR(PARSER_LINE_FORMAT_ERROR, begin);
		return;
	}

	return;
}

std::string wolv::condition::Parser::_getWord( const char*& start , bool readLineBreak/* = false*/)
{
	const char * wordStart = start;
	while (*wordStart != '\0')
	{
		if (*wordStart != '\t' && *wordStart != ' ')
		{
			break;
		}
		wordStart++;
	}

	const char * wordEnd = wordStart;
	
	if (*wordEnd == '"') // parse quoted escape string
	{
		std::string result;

		++wordEnd;
		while (*wordEnd != '\0')
		{
			if (*wordEnd == '"')
			{
				break;
			}

			if (*wordEnd == '\\')
			{
				char escape = 0;
				++wordEnd;

				if (*wordEnd == '\0')
				{
					break;
				}

				result.append(1, _escape(escape));
			}
			else
			{
				result.append(1, *wordEnd);
			}
		}

		start = wordEnd;

		return result;
	}
	else 
	{
		while (*wordEnd != '\0' && *wordEnd != ' ')
		{
			if (!readLineBreak && *wordEnd == '\n')
			{
				break;
			}
			if (readLineBreak && *wordEnd == '\n')
			{
				++wordEnd;
				break;
			}
			++wordEnd;
		}

		start = wordEnd;

		return std::string(wordStart, wordEnd);
	}
}

char Parser::_escape( char _escape )
{
	switch (*_escape)
	{
	case '\'': 
		return '\'';
	case 'n':
		return '\n';
	case 't':
		return '\t';
	case 'r':
		return '\r';
	case 'b':
		return '\b';
	case 'a':
		return '\a';
	default:
		return _escape;
	}
}

